#ifndef FILESYSTEM_HPP
#define FILESYSTEM_HPP

#include <iostream>
#include <string>
#include <vector>
#include <map>
#include <mutex>
#include <optional>
#include <iomanip> // for std::setw
#include <sstream> // for std::stringstream

// 模拟磁盘总大小 (盘块数)
const int DISK_SIZE = 128;

// 文件控制块 (File Control Block)
struct FCB {
    std::string fileName;
    int protectionCode; // 保护码: 1=只读, 2=只写, 3=读写, 0=无权限
    int startBlock;     // 物理地址 (起始盘块号)
    int fileLength;     // 文件长度 (字节数)
    std::string content;// 模拟文件内容  内存级
};

// 用户文件目录 (User File Directory)
using UFD = std::map<std::string, FCB>;

// 用户账户
struct User {
    std::string password;
    UFD ufd;  // 这个passwd 下用户的所有文件和文件名的映射。
};

// 主文件目录 (Master File Directory)   用户名和用户结构体
using MFD = std::map<std::string, User>; 

// 用户打开文件表项
struct UserOpenFile {
    std::string fileName;
    int protectionCode;
};


class FileSystem {
public:
    // 获取文件系统的单例实例
    static FileSystem& instance() {
        static FileSystem fs_instance;
        return fs_instance;
    }

    // 禁止拷贝和赋值
    FileSystem(const FileSystem&) = delete;
    FileSystem& operator=(const FileSystem&) = delete;

    // --- 命令处理接口 ---
    void login(const std::string& username, const std::string& password) {
        std::lock_guard<std::mutex> lock(fs_mutex); // 保证线程安全
        
        // 检查用户是否存在，如果不存在则自动注册
        if (mfd.find(username) == mfd.end()) {
            mfd[username] = {password, {}};
            std::cout << "[INFO] User '" << username << "' not found. Registered automatically.\n";
        }
        
        // 检查密码
        if (mfd.at(username).password == password) {
            currentUser.emplace(username); // C++17 emplace
            std::cout << "[SUCCESS] User '" << username << "' logged in.\n";
        } else {
            std::cout << "[ERROR] Incorrect password for user '" << username << "'.\n";
        }
    }

    void logout() {
        std::lock_guard<std::mutex> lock(fs_mutex);
        if (!currentUser) {
            std::cout << "[ERROR] No user is currently logged in.\n";
            return;
        }
        std::cout << "[SUCCESS] User '" << *currentUser << "' logged out.\n";
        currentUser.reset();
        userOpenFiles.clear(); // 用户登出时关闭其所有打开的文件
    }

    void dir() {
        std::lock_guard<std::mutex> lock(fs_mutex);
        if (!check_login()) return;
        
        auto& ufd = mfd.at(*currentUser).ufd;
        if (ufd.empty()) {
            std::cout << "Directory is empty.\n";
            return;
        }

        std::cout << std::left
                  << std::setw(20) << "File Name"
                  << std::setw(15) << "Physical Addr"
                  << std::setw(15) << "Protection"
                  << std::setw(15) << "Length(Bytes)"
                  << std::endl;
        std::cout << std::string(65, '-') << std::endl;

        for (const auto& pair : ufd) {
            const auto& fcb = pair.second;
            std::cout << std::left
                      << std::setw(20) << fcb.fileName
                      << std::setw(15) << fcb.startBlock
                      << std::setw(15) << protection_to_string(fcb.protectionCode)
                      << std::setw(15) << fcb.fileLength
                      << std::endl;
        }
    }

    void create(const std::string& fileName, int protectionCode) {
        std::lock_guard<std::mutex> lock(fs_mutex);
        if (!check_login()) return;

        auto& ufd = mfd.at(*currentUser).ufd;
        if (ufd.count(fileName)) {
            std::cout << "[ERROR] File '" << fileName << "' already exists.\n";
            return;
        }

        int block = find_free_block();
        if (block == -1) {
            std::cout << "[ERROR] Disk is full. Cannot create file.\n";
            return;
        }

        fat[block] = true; // 占用该盘块
        FCB newFcb = {fileName, protectionCode, block, 0, ""};
        ufd[fileName] = newFcb;
        std::cout << "[SUCCESS] File '" << fileName << "' created.\n";
    }

    void del(const std::string& fileName) {
        std::lock_guard<std::mutex> lock(fs_mutex);
        if (!check_login()) return;

        auto& ufd = mfd.at(*currentUser).ufd;
        if (!ufd.count(fileName)) {
            std::cout << "[ERROR] File '" << fileName << "' not found.\n";
            return;
        }

        // 如果文件被打开，则不能删除
        if (is_file_open_by_user(fileName)) {
            std::cout << "[ERROR] File '" << fileName << "' is currently open. Please close it first.\n";
            return;
        }
        
        fat[ufd.at(fileName).startBlock] = false; // 释放盘块
        ufd.erase(fileName);
        std::cout << "[SUCCESS] File '" << fileName << "' deleted.\n";
    }

    void open(const std::string& fileName) {
        std::lock_guard<std::mutex> lock(fs_mutex);
        if (!check_login()) return;

        auto& ufd = mfd.at(*currentUser).ufd;
        if (!ufd.count(fileName)) {
            std::cout << "[ERROR] File '" << fileName << "' not found.\n";
            return;
        }
        if (is_file_open_by_user(fileName)) {
            std::cout << "[INFO] File '" << fileName << "' is already open.\n";
            return;
        }
        
        const auto& fcb = ufd.at(fileName);
        UserOpenFile uof = {fcb.fileName, fcb.protectionCode};
        userOpenFiles.push_back(uof);
        std::cout << "[SUCCESS] File '" << fileName << "' opened.\n";
    }

    void close(const std::string& fileName) {
        std::lock_guard<std::mutex> lock(fs_mutex);
        if (!check_login()) return;

        for (auto it = userOpenFiles.begin(); it != userOpenFiles.end(); ++it) {
            if (it->fileName == fileName) {
                userOpenFiles.erase(it);
                std::cout << "[SUCCESS] File '" << fileName << "' closed.\n";
                return;
            }
        }
        std::cout << "[ERROR] File '" << fileName << "' is not open.\n";
    }

    void read(const std::string& fileName) {
        std::lock_guard<std::mutex> lock(fs_mutex);
        if (!check_login()) return;

        auto openFile = find_user_open_file(fileName);
        if (!openFile) {
            std::cout << "[ERROR] File '" << fileName << "' is not open. Please open it first.\n";
            return;
        }
        
        // 检查读权限 (1=只读, 3=读写)
        if (openFile->protectionCode != 1 && openFile->protectionCode != 3) {
            std::cout << "[ERROR] Permission denied. Cannot read file '" << fileName << "'.\n";
            return;
        }
        
        const auto& fcb = mfd.at(*currentUser).ufd.at(fileName);
        std::cout << "--- Content of " << fileName << " ---\n";
        std::cout << (fcb.content.empty() ? "[Empty File]" : fcb.content) << std::endl;
        std::cout << "--- End of Content ---\n";
    }

    void write(const std::string& fileName, const std::string& content) {
        std::lock_guard<std::mutex> lock(fs_mutex);
        if (!check_login()) return;

        auto openFile = find_user_open_file(fileName);
        if (!openFile) {
            std::cout << "[ERROR] File '" << fileName << "' is not open. Please open it first.\n";
            return;
        }

        // 检查写权限 (2=只写, 3=读写)
        if (openFile->protectionCode != 2 && openFile->protectionCode != 3) {
            std::cout << "[ERROR] Permission denied. Cannot write to file '" << fileName << "'.\n";
            return;
        }

        auto& fcb = mfd.at(*currentUser).ufd.at(fileName);
        fcb.content = content;
        fcb.fileLength = content.length();
        std::cout << "[SUCCESS] Wrote to file '" << fileName << "'.\n";
    }


private:
    FileSystem() : fat(DISK_SIZE, false) {} // 私有构造函数

    bool check_login() {
        if (!currentUser) {
            std::cout << "[ERROR] You must be logged in to perform this action.\n";
            return false;
        }
        return true;
    }
    
    std::string protection_to_string(int code) {
        switch (code) {
            case 1: return "r";
            case 2: return "w";
            case 3: return "rw";
            default: return "-";
        }
    }

    int find_free_block() {
        for (int i = 0; i < DISK_SIZE; ++i) {
            if (!fat[i]) {
                return i;
            }
        }
        return -1; // No free block
    }
    
    bool is_file_open_by_user(const std::string& fileName) {
        for (const auto& uof : userOpenFiles) {
            if (uof.fileName == fileName) {
                return true;
            }
        }
        return false;
    }
    
    std::optional<UserOpenFile> find_user_open_file(const std::string& fileName) {
        for (const auto& uof : userOpenFiles) {
            if (uof.fileName == fileName) {
                return uof;
            }
        }
        return std::nullopt;
    }
    
    std::mutex fs_mutex; // 保护整个文件系统数据结构的互斥锁
    MFD mfd;             // 主文件目录
    std::vector<bool> fat; // 文件分配表 (位图法)
    
    // 以下状态是线程相关的，但由于我们的命令在一个线程中执行完毕，
    // 并且有 fs_mutex 保护，所以可以作为类的成员。
    // 如果要支持多用户同时在线，currentUser 需要是 thread_local 的。
    // 这里为了简化，我们假设命令行同一时间只有一个用户上下文。
    std::optional<std::string> currentUser;
    std::vector<UserOpenFile> userOpenFiles;
};

#endif // FILESYSTEM_HPP
